package com.momo.hystrix.controller;

import com.momo.hystrix.service.HelloService;
import com.momo.hystrix.service.UserService;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import pojo.User;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@RestController
public class HelloController {

    @Autowired
    HelloService helloService;

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    UserService userService;

    @GetMapping("/hello")
    public String hello(){
        return helloService.hello();

    }

    @GetMapping("/helloCommand")
    public String helloCommand(String name){
        /*
           需要开启缓存 不然无法使用请求缓存
         */
        HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
        /**
         * 使用继承的方式进行调用
         */
        HelloCommand momo = new HelloCommand(HystrixCommand
                .Setter
                .withGroupKey(HystrixCommandGroupKey.Factory.asKey("momo")),restTemplate,"momo");
        /**
         * 第一种实现方式使用execute来就行执行熔断操作
         */
        momo.execute();
        /**
         * 使用队列来实现熔断方法的执行操作 【异步调用】先入队列然后执行
         */
        String s = null;
        try {
            s = momo.queue().get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        ctx.close();
        return s;
    }

    /**
     * 异步容错的方法
     */
    @GetMapping("/helloAsync")
    public String helloAsync(){
        try {
            return helloService.hello2().get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return "错误";
    }


    /**
     * 带有异常信息返回值的的请求
     * @return
     */
    @GetMapping("/consumerException")
    public String consumerException(){
        try {
            return helloService.hello2().get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return "错误";
    }

    /**
     * 带有缓存请求的,，
     * 使用会发现provider中的请求只回被请求一次。
     * 1、默认情况下缓存的key就是调用方法的参数，如果参数有多个，如果参数组合起来。
     * 2、应为Service加了 @CacheKey 所以会根据我们的key 是否一样来进行判别此次请求是否缓存
     * @return
     */
    @GetMapping("/consumerWithCache")
    public String consumerWithCache(){
        /*
            当然这只是测试环境下这样初始化,
            真正的web项目是在filter中进行初始化的,
            （有两种方式：首先都要要实现filter重写其方法,
            一种是采用注解的方式@WebFilter,
            别忘了在启动类上添加@ServletComponentScan注解,
            另一种是Java代码注册的方式会用到FilterRegistrationBean这个类。
            这里会由于name 的值不一样，会子昂provider发起两次请求
         */
        HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
        String momo = this.helloService.hello3WithRequestCacheByCacheKey("momo",22);
        momo = this.helloService.hello3WithRequestCacheByCacheKey("momo",22);
        ctx.close();
        return momo;
    }

    /**
     * 通过 @CacheRemove 来删除缓存
     * 所以这次两次请求都会发起，因为第一次的请求的缓存数据已经被我们删除了
     * 所以这里provider会收到两次请求
     * @return
     */
    @GetMapping("/consumerWithCacheRemove")
    public String consumerWithCacheRemove(){
        /*
            当然这只是测试环境下这样初始化,
            真正的web项目是在filter中进行初始化的,
            （有两种方式：首先都要要实现filter重写其方法,
            一种是采用注解的方式@WebFilter,
            别忘了在启动类上添加@ServletComponentScan注解,
            另一种是Java代码注册的方式会用到FilterRegistrationBean这个类。
         */
        HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
        /*
            这里注意我们需要调用带有@CacherRemove的的放方法进行删除缓存的方法
         */
        String momo = this.helloService.hello3WithRequestCache("momo");
        this.helloService.deleteUserWithRequestCacheByCacheRemove("momo");
        momo = this.helloService.hello3WithRequestCache("momo");
        ctx.close();
        return momo;
    }

    /**
     * 批处理请求
     */
    @GetMapping("/helloWithBatchRequest")
    public void helloWithBatchRequest() throws ExecutionException, InterruptedException {
        HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
        UserCollapseCommand userCollapseCommand1 = new UserCollapseCommand(userService,99);
        UserCollapseCommand userCollapseCommand2 = new UserCollapseCommand(userService,98);
        UserCollapseCommand userCollapseCommand3 = new UserCollapseCommand(userService,97);
        UserCollapseCommand userCollapseCommand4 = new UserCollapseCommand(userService,96);
        Future<User> queue1 = userCollapseCommand1.queue();
        Future<User> queue2 = userCollapseCommand2.queue();
        Future<User> queue3 = userCollapseCommand3.queue();
        Future<User> queue4 = userCollapseCommand4.queue();
        User user1 = queue1.get();
        User user2 = queue2.get();
        User user3 = queue3.get();
        User user4 = queue4.get();
        System.out.println(user1.toString());
        System.out.println(user2.toString());
        System.out.println(user3.toString());
        System.out.println(user4.toString());
        ctx.close();
    }

    /**
     * 使用注解来实现合并请求
     * @throws ExecutionException
     * @throws InterruptedException
     */
    @GetMapping("/helloWithBatchRequest")
    public void helloWithBatchRequest2() throws ExecutionException, InterruptedException {
        HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
        Future<User> userCollapseCommand1 = userService.getUserById(99);
        Future<User> userCollapseCommand2 = userService.getUserById(98);
        Future<User> userCollapseCommand3 = userService.getUserById(97);
        Future<User> userCollapseCommand4 = userService.getUserById(96);
        User user1 = userCollapseCommand1.get();
        User user2 = userCollapseCommand2.get();
        User user3 = userCollapseCommand3.get();
        User user4 = userCollapseCommand4.get();
        System.out.println(user1.toString());
        System.out.println(user2.toString());
        System.out.println(user3.toString());
        System.out.println(user4.toString());
        ctx.close();
    }
}
